package com.workerhelping.service.impl;

import com.alibaba.fastjson.JSON;
import com.workerhelping.dao.ESRecordVODao;
import com.workerhelping.elasticsearchEntity.ESRecordVO;
import com.workerhelping.enums.elasticsearch.ESIndicesEnum;
import com.workerhelping.enums.RecordStatusEnum;
import com.workerhelping.enums.elasticsearch.ESRecordFieldEnum;
import com.workerhelping.service.ESRecordVOService;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;

@Slf4j
@Service
public class ESRecordVOServiceImpl implements ESRecordVOService {
    @Autowired
    private ESRecordVODao esRecordVODao;

    @Autowired
    private RestHighLevelClient restHighLevelClient;


    @Override
    public void insertOrUpdate(ESRecordVO esRecordVO) {
        esRecordVODao.save(esRecordVO);
    }

    @Override
    public void delete(ESRecordVO esRecordVO) {
        esRecordVODao.delete(esRecordVO);
    }

    @Override
    public List<ESRecordVO> findAllByUnreviewed(Integer id, String name, String idNumber, String creditCardNumbers) throws Exception {
        return search(id, name, idNumber, creditCardNumbers, RecordStatusEnum.UNREVIEWED);
    }

    @Override
    public List<ESRecordVO> findAllByApproved(Integer id, String name, String idNumber, String creditCardNumbers) throws Exception {
        return search(id, name, idNumber, creditCardNumbers, RecordStatusEnum.APPROVED);

    }

    @Override
    public List<ESRecordVO> findAllByRejected(Integer id, String name, String idNumber, String creditCardNumbers) throws Exception {
        return search(id, name, idNumber, creditCardNumbers, RecordStatusEnum.REJECTED);

    }

    @Override
    public List<ESRecordVO> findAllByCancelled(Integer id, String name, String idNumber, String creditCardNumbers) throws Exception {
        return search(id, name, idNumber, creditCardNumbers, RecordStatusEnum.CANCELLED);
    }


    /**
     * 公共方法
     *
     * @param id 字段查询
     * @param name 模糊查询
     * @param idNumber 通配符查询
     * @param creditCardNumbers 通配符查询
     * @param statusEnum 必要条件
     * @return
     * @throws Exception
     */
    private List<ESRecordVO> search(Integer id,
                                    String name,
                                    String idNumber,
                                    String creditCardNumbers,
                                    RecordStatusEnum statusEnum) throws Exception {
        ArrayList<ESRecordVO> result = new ArrayList<>();
        SearchRequest searchRequest = new SearchRequest();
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 全局布尔查询
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        // 拼接必要条件
        boolQuery.must(QueryBuilders.termQuery(ESRecordFieldEnum.STATUS.getField(), statusEnum.getStatus()));

        if (!StringUtils.isEmpty(id))
            boolQuery.must(QueryBuilders.termQuery(ESRecordFieldEnum.ID.getField(), id));
        if (!StringUtils.isEmpty(name))
            boolQuery.must(QueryBuilders.fuzzyQuery(ESRecordFieldEnum.NAME.getField(), name));
        if (!StringUtils.isEmpty(idNumber))
            boolQuery.must(QueryBuilders.wildcardQuery(ESRecordFieldEnum.IDNUMBER.getField(), "*" + idNumber + "*"));
        if (!StringUtils.isEmpty(creditCardNumbers))
            boolQuery.must(QueryBuilders.wildcardQuery(ESRecordFieldEnum.CREDITCARDNUMBERS.getField(), "*" + creditCardNumbers + "*"));


        // 公共部分 依赖布尔查询
        sourceBuilder.from(0).size(1000).sort(ESRecordFieldEnum.ID.getField(), SortOrder.ASC).size(1000).query(boolQuery);
        searchRequest.indices(ESIndicesEnum.RECORD.getName()).
                types(ESIndicesEnum.RECORD.getName()).
                source(sourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        SearchHit[] hits = searchResponse.getHits().getHits();
        for (SearchHit hit : hits) {
            String sourceAsString = hit.getSourceAsString();
            ESRecordVO recordVO = JSON.parseObject(sourceAsString, ESRecordVO.class);
            result.add(recordVO);
        }
        return result;
    }
}
